{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Created agent, ID: asst_IKkHJZ4W6aiFApkMFlmXmHYe\n",
      "Created thread, ID: thread_fKnWZffmD2ZHS2OAnzmZVyQK\n",
      "Created message, ID: msg_QBJMnu9bQMmJb91OxWXM78wg\n"
     ]
    },
    {
     "ename": "HttpResponseError",
     "evalue": "(invalid_type) Invalid type for 'tool_outputs[0].output': expected a string, but got an object instead.\nCode: invalid_type\nMessage: Invalid type for 'tool_outputs[0].output': expected a string, but got an object instead.",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mHttpResponseError\u001b[0m                         Traceback (most recent call last)",
      "Cell \u001b[0;32mIn[3], line 45\u001b[0m\n\u001b[1;32m     41\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mCreated message, ID: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mmessage\u001b[38;5;241m.\u001b[39mid\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m\"\u001b[39m)\n\u001b[1;32m     43\u001b[0m \u001b[38;5;66;03m# Create and process agent run in thread with tools\u001b[39;00m\n\u001b[1;32m     44\u001b[0m \u001b[38;5;66;03m# [START create_and_process_run]\u001b[39;00m\n\u001b[0;32m---> 45\u001b[0m run \u001b[38;5;241m=\u001b[39m \u001b[43mproject_client\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43magents\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mcreate_and_process_run\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m     46\u001b[0m \u001b[43m    \u001b[49m\u001b[43mthread_id\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mthread\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mid\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43massistant_id\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43magent\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mid\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m     48\u001b[0m \u001b[38;5;66;03m# [END create_and_process_run]\u001b[39;00m\n\u001b[1;32m     49\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mRun finished with status: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mrun\u001b[38;5;241m.\u001b[39mstatus\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m\"\u001b[39m)\n",
      "File \u001b[0;32m~/ai-agents-for-beginners/.venv/lib/python3.11/site-packages/azure/core/tracing/decorator.py:105\u001b[0m, in \u001b[0;36mdistributed_trace.<locals>.decorator.<locals>.wrapper_use_tracer\u001b[0;34m(*args, **kwargs)\u001b[0m\n\u001b[1;32m    103\u001b[0m span_impl_type \u001b[38;5;241m=\u001b[39m settings\u001b[38;5;241m.\u001b[39mtracing_implementation()\n\u001b[1;32m    104\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m span_impl_type \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[0;32m--> 105\u001b[0m     \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mfunc\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43margs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m    107\u001b[0m \u001b[38;5;66;03m# Merge span is parameter is set, but only if no explicit parent are passed\u001b[39;00m\n\u001b[1;32m    108\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m merge_span \u001b[38;5;129;01mand\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m passed_in_parent:\n",
      "File \u001b[0;32m~/ai-agents-for-beginners/.venv/lib/python3.11/site-packages/azure/ai/projects/operations/_patch.py:1791\u001b[0m, in \u001b[0;36mAgentsOperations.create_and_process_run\u001b[0;34m(self, thread_id, assistant_id, include, model, instructions, additional_instructions, additional_messages, toolset, temperature, top_p, max_prompt_tokens, max_completion_tokens, truncation_strategy, tool_choice, response_format, parallel_tool_calls, metadata, sleep_interval, **kwargs)\u001b[0m\n\u001b[1;32m   1789\u001b[0m             logging\u001b[38;5;241m.\u001b[39minfo(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mTool outputs: \u001b[39m\u001b[38;5;132;01m%s\u001b[39;00m\u001b[38;5;124m\"\u001b[39m, tool_outputs)\n\u001b[1;32m   1790\u001b[0m             \u001b[38;5;28;01mif\u001b[39;00m tool_outputs:\n\u001b[0;32m-> 1791\u001b[0m                 \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43msubmit_tool_outputs_to_run\u001b[49m\u001b[43m(\u001b[49m\u001b[43mthread_id\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mthread_id\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mrun_id\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mrun\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mid\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mtool_outputs\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mtool_outputs\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m   1793\u001b[0m     logging\u001b[38;5;241m.\u001b[39minfo(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mCurrent run status: \u001b[39m\u001b[38;5;132;01m%s\u001b[39;00m\u001b[38;5;124m\"\u001b[39m, run\u001b[38;5;241m.\u001b[39mstatus)\n\u001b[1;32m   1795\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m run\n",
      "File \u001b[0;32m~/ai-agents-for-beginners/.venv/lib/python3.11/site-packages/azure/core/tracing/decorator.py:105\u001b[0m, in \u001b[0;36mdistributed_trace.<locals>.decorator.<locals>.wrapper_use_tracer\u001b[0;34m(*args, **kwargs)\u001b[0m\n\u001b[1;32m    103\u001b[0m span_impl_type \u001b[38;5;241m=\u001b[39m settings\u001b[38;5;241m.\u001b[39mtracing_implementation()\n\u001b[1;32m    104\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m span_impl_type \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[0;32m--> 105\u001b[0m     \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mfunc\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43margs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m    107\u001b[0m \u001b[38;5;66;03m# Merge span is parameter is set, but only if no explicit parent are passed\u001b[39;00m\n\u001b[1;32m    108\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m merge_span \u001b[38;5;129;01mand\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m passed_in_parent:\n",
      "File \u001b[0;32m~/ai-agents-for-beginners/.venv/lib/python3.11/site-packages/azure/ai/projects/operations/_patch.py:2346\u001b[0m, in \u001b[0;36mAgentsOperations.submit_tool_outputs_to_run\u001b[0;34m(self, thread_id, run_id, body, tool_outputs, **kwargs)\u001b[0m\n\u001b[1;32m   2343\u001b[0m     response \u001b[38;5;241m=\u001b[39m \u001b[38;5;28msuper\u001b[39m()\u001b[38;5;241m.\u001b[39msubmit_tool_outputs_to_run(thread_id, run_id, body, content_type\u001b[38;5;241m=\u001b[39mcontent_type, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs)\n\u001b[1;32m   2345\u001b[0m \u001b[38;5;28;01melif\u001b[39;00m tool_outputs \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m _Unset:\n\u001b[0;32m-> 2346\u001b[0m     response \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43msuper\u001b[39;49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43msubmit_tool_outputs_to_run\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m   2347\u001b[0m \u001b[43m        \u001b[49m\u001b[43mthread_id\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m   2348\u001b[0m \u001b[43m        \u001b[49m\u001b[43mrun_id\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m   2349\u001b[0m \u001b[43m        \u001b[49m\u001b[43mtool_outputs\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mtool_outputs\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m   2350\u001b[0m \u001b[43m        \u001b[49m\u001b[43mstream_parameter\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43;01mFalse\u001b[39;49;00m\u001b[43m,\u001b[49m\n\u001b[1;32m   2351\u001b[0m \u001b[43m        \u001b[49m\u001b[43mstream\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43;01mFalse\u001b[39;49;00m\u001b[43m,\u001b[49m\n\u001b[1;32m   2352\u001b[0m \u001b[43m        \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m   2353\u001b[0m \u001b[43m    \u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m   2355\u001b[0m \u001b[38;5;28;01melif\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(body, io\u001b[38;5;241m.\u001b[39mIOBase):\n\u001b[1;32m   2356\u001b[0m     content_type \u001b[38;5;241m=\u001b[39m kwargs\u001b[38;5;241m.\u001b[39mget(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mcontent_type\u001b[39m\u001b[38;5;124m\"\u001b[39m, \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mapplication/json\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n",
      "File \u001b[0;32m~/ai-agents-for-beginners/.venv/lib/python3.11/site-packages/azure/core/tracing/decorator.py:105\u001b[0m, in \u001b[0;36mdistributed_trace.<locals>.decorator.<locals>.wrapper_use_tracer\u001b[0;34m(*args, **kwargs)\u001b[0m\n\u001b[1;32m    103\u001b[0m span_impl_type \u001b[38;5;241m=\u001b[39m settings\u001b[38;5;241m.\u001b[39mtracing_implementation()\n\u001b[1;32m    104\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m span_impl_type \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[0;32m--> 105\u001b[0m     \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mfunc\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43margs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m    107\u001b[0m \u001b[38;5;66;03m# Merge span is parameter is set, but only if no explicit parent are passed\u001b[39;00m\n\u001b[1;32m    108\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m merge_span \u001b[38;5;129;01mand\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m passed_in_parent:\n",
      "File \u001b[0;32m~/ai-agents-for-beginners/.venv/lib/python3.11/site-packages/azure/ai/projects/operations/_operations.py:4093\u001b[0m, in \u001b[0;36mAgentsOperations.submit_tool_outputs_to_run\u001b[0;34m(self, thread_id, run_id, body, tool_outputs, stream_parameter, **kwargs)\u001b[0m\n\u001b[1;32m   4091\u001b[0m             \u001b[38;5;28;01mpass\u001b[39;00m\n\u001b[1;32m   4092\u001b[0m     map_error(status_code\u001b[38;5;241m=\u001b[39mresponse\u001b[38;5;241m.\u001b[39mstatus_code, response\u001b[38;5;241m=\u001b[39mresponse, error_map\u001b[38;5;241m=\u001b[39merror_map)\n\u001b[0;32m-> 4093\u001b[0m     \u001b[38;5;28;01mraise\u001b[39;00m HttpResponseError(response\u001b[38;5;241m=\u001b[39mresponse)\n\u001b[1;32m   4095\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m _stream:\n\u001b[1;32m   4096\u001b[0m     deserialized \u001b[38;5;241m=\u001b[39m response\u001b[38;5;241m.\u001b[39miter_bytes()\n",
      "\u001b[0;31mHttpResponseError\u001b[0m: (invalid_type) Invalid type for 'tool_outputs[0].output': expected a string, but got an object instead.\nCode: invalid_type\nMessage: Invalid type for 'tool_outputs[0].output': expected a string, but got an object instead."
     ]
    }
   ],
   "source": [
    "import os\n",
    "from azure.ai.projects import AIProjectClient\n",
    "from azure.identity import DefaultAzureCredential\n",
    "from azure.ai.projects.models import FunctionTool, ToolSet, CodeInterpreterTool\n",
    "from user_functions import user_functions\n",
    "\n",
    "project_client = AIProjectClient.from_connection_string(\n",
    "    credential=DefaultAzureCredential(),\n",
    "    conn_str=os.environ[\"PROJECT_CONNECTION_STRING\"],\n",
    ")\n",
    "\n",
    "with project_client:\n",
    "    # Initialize agent toolset with user functions and code interpreter\n",
    "    # [START create_agent_toolset]\n",
    "    functions = FunctionTool(user_functions)\n",
    "    code_interpreter = CodeInterpreterTool()\n",
    "\n",
    "    toolset = ToolSet()\n",
    "    toolset.add(functions)\n",
    "    toolset.add(code_interpreter)\n",
    "\n",
    "    agent = project_client.agents.create_agent(\n",
    "        model=\"gpt-4o-mini\",\n",
    "        name=\"my-assistant\",\n",
    "        instructions=\"You are a travel assitant that can lookup past flight data for users given the city and time period. First convert city names to airport codes, then use the airport codes to query the flight data. Answer the questions as accurately as possible using the provided functions.\",\n",
    "        toolset=toolset,\n",
    "    )\n",
    "    # [END create_agent_toolset]\n",
    "    print(f\"Created agent, ID: {agent.id}\")\n",
    "\n",
    "    # Create thread for communication\n",
    "    thread = project_client.agents.create_thread()\n",
    "    print(f\"Created thread, ID: {thread.id}\")\n",
    "\n",
    "    # Create message to thread\n",
    "    message = project_client.agents.create_message(\n",
    "        thread_id=thread.id,\n",
    "        role=\"user\",\n",
    "        content=\"Can you tell me about the fligght with a call sign DLH8JT?\",\n",
    "    )\n",
    "    print(f\"Created message, ID: {message.id}\")\n",
    "\n",
    "    # Create and process agent run in thread with tools\n",
    "    # [START create_and_process_run]\n",
    "    run = project_client.agents.create_and_process_run(\n",
    "        thread_id=thread.id, assistant_id=agent.id)\n",
    "    \n",
    "    # [END create_and_process_run]\n",
    "    print(f\"Run finished with status: {run.status}\")\n",
    "\n",
    "    if run.status == \"failed\":\n",
    "        print(f\"Run failed: {run.last_error}\")\n",
    "\n",
    "    # Delete the assistant when done\n",
    "    project_client.agents.delete_agent(agent.id)\n",
    "    print(\"Deleted agent\")\n",
    "\n",
    "    # Fetch and log all messages\n",
    "    messages = project_client.agents.list_messages(thread_id=thread.id)\n",
    "    print(f\"Messages: {messages}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "ename": "NameError",
     "evalue": "name 'messages' is not defined",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mNameError\u001b[0m                                 Traceback (most recent call last)",
      "Cell \u001b[0;32mIn[4], line 21\u001b[0m\n\u001b[1;32m     15\u001b[0m         formatted_messages\u001b[38;5;241m.\u001b[39mappend(\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mrole\u001b[38;5;241m.\u001b[39mcapitalize()\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mcontent\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m\"\u001b[39m)\n\u001b[1;32m     17\u001b[0m     \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;130;01m\\n\u001b[39;00m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;241m.\u001b[39mjoin(formatted_messages)\n\u001b[0;32m---> 21\u001b[0m \u001b[38;5;28mprint\u001b[39m(format_messages(\u001b[43mmessages\u001b[49m))\n",
      "\u001b[0;31mNameError\u001b[0m: name 'messages' is not defined"
     ]
    }
   ],
   "source": [
    "import json\n",
    "from datetime import datetime\n",
    "\n",
    "def format_messages(messages):\n",
    "    \"\"\"\n",
    "    Format the messages to look like a conversation and reverse the order of the messages.\n",
    "\n",
    "    :param messages: The messages to format.\n",
    "    :return: A formatted string representing the conversation.\n",
    "    \"\"\"\n",
    "    formatted_messages = []\n",
    "    for message in reversed(messages['data']):\n",
    "        role = message['role']\n",
    "        content = message['content'][0]['text']['value']\n",
    "        formatted_messages.append(f\"{role.capitalize()}: {content}\")\n",
    "\n",
    "    return \"\\n\".join(formatted_messages)\n",
    "\n",
    "\n",
    "\n",
    "print(format_messages(messages))\n",
    "\n"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": ".venv",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.8"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
